package com.listeningframework.boot.commons.reflect;

import com.google.common.collect.Lists;
import com.listeningframework.boot.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * 
 * Java Reflect Utils
 *  
 * @author listening
 * @version $Id: ListeningReflectUtils.java, v 0.1 2015年6月11日 下午10:36:56 listening Exp $
 */
public class ReflectUtils {

    /**
     * Java动态添加library path
     *
     * @param path 路径
     */
    public static final void addLibraryPath(String path) {
        try {
            String libraryPath = System.getProperty("java.library.path");
            System.setProperty("java.library.path", libraryPath + ";" + path);
            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            throw new RuntimeException("add library path fail");
        }
    }

    /**
     * Java动态添加library path
     */
    public static final void addLibrarySigarPath() {
        String path = ReflectUtils.class.getResource("/libsigar").getPath();
        addLibraryPath(path);
    }

    /**
     * 获取泛型参数Class
     * 
     * @param cls 类
     * @return Class
     */
    public static Class<?> getGenericClass(Class<?> cls) {
        if (cls == null || cls.getGenericSuperclass() == null) {
            return null;
        }
        Type type = cls.getGenericSuperclass();
        if (!(type instanceof ParameterizedType)) {
            return null;
        }
        ParameterizedType parameterType = (ParameterizedType) type;
        return (Class<?>) parameterType.getActualTypeArguments()[0];
    }

    /**
     * 泛型参数名称
     * 
     * @param cls Class类
     * @return String
     */
    public static final String getGenericClassName(Class<?> cls) {
        Class<?> genericClass = getGenericClass(cls);
        return genericClass == null ? null : genericClass.getSimpleName();
    }

    /**
     * 类型是否一致
     *
     * @param sourceClz 源Class
     * @param compareClz 目标Class
     * @return boolean
     */
    public static final boolean isType(Class<?> sourceClz, Class<?> compareClz) {
        return StringUtils.equals(sourceClz.getName(), compareClz.getName());
    }

    /**
     * 根据Class实例一个对象
     *
     * @param clz 类Class
     * @param <T> 泛型Class
     * @return T
     * @throws BusinessException 异常
     */
    public static final <T> T newInstance(Class<T> clz) throws BusinessException {
        try {
            return clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BusinessException("Construct Clz Fail", e);
        }
    }

    /**
     * 根据Class实例一个对象
     *
     * @param clz 类Class
     * @param <T> 泛型Class
     * @return T
     */
    public static final <T> T safenewInstance(Class<T> clz) {
        try {
            return clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("Construct Clz Fail", e);
        }
    }

    /**
     * Find Annotation Fields
     *
     * @param clz 类Class
     * @param annotationClass 注解Class
     * @return List
     */
    public static final List<Field> findAnnotationFields(Class<?> clz, Class<? extends Annotation> annotationClass) {
        List<Field> fieldList = Lists.newArrayList();
        Field[] fieldArray = clz.getDeclaredFields();
        if (fieldArray == null || fieldArray.length == 0) {
            return fieldList;
        }
        for (Field field : fieldArray) {
            if (field.isAnnotationPresent(annotationClass)) {
                fieldList.add(field);
            }
        }
        return fieldList;
    }
}
